package production

import (
	"context"
	"errors"
	"github.com/google/uuid"
	"github.com/shopspring/decimal"
	"insighttracking/apps/sorting/auth"
	"insighttracking/common/enum"
	"insighttracking/common/utils"
	"insighttracking/query/dao"
	"insighttracking/query/model"
	"insighttracking/query/service"
	"net/http"
	"time"

	"insighttracking/apps/sorting/internal/svc"
	"insighttracking/apps/sorting/internal/types"

	"github.com/zeromicro/go-zero/core/logx"
	"os"
)

type ApiLogic struct {
	logx.Logger
	ctx     context.Context
	svcCtx  *svc.ServiceContext
	Request *http.Request
}

func NewApiLogic(ctx context.Context, svcCtx *svc.ServiceContext, request *http.Request) *ApiLogic {
	hostname, _ := os.Hostname()
	return &ApiLogic{
		Logger: logx.WithContext(ctx).WithCallerSkip(0).WithFields(
			logx.Field("Log_UUID", uuid.New().String()),
			logx.Field("hostname", hostname)),
		ctx:     ctx,
		svcCtx:  svcCtx,
		Request: request,
	}
}

func (l *ApiLogic) GetListApi(req *types.ProductionListReq) (resp *types.ProductionListResp, err error) {
	resp = &types.ProductionListResp{}
	accountInfo, err := auth.GetAccountInfo(l.svcCtx, l.Request)
	if err != nil {
		return nil, err
	}
	if req.StartDate == "" {
		req.StartDate = time.Now().Format("2006-01-02")
	}
	if req.EndDate == "" {
		req.EndDate = time.Now().Add(time.Hour * 48).Format("2006-01-02")
	}
	entities, err := service.ProductionPlanService.GetListApi(l.ctx, accountInfo.EnterpriseId, req.StartDate, req.EndDate)
	if err != nil {
		return nil, err
	}
	list := make([]*types.ProductionList, 0)
	for _, entity := range entities {
		var count int64
		count, _ = service.ProductionPlanService.GetTypeCountByPlanIDApi(l.ctx, entity.ID)
		list = append(list, &types.ProductionList{
			Code:            entity.Code,
			ID:              entity.ID,
			Name:            entity.Name,
			ProduceDate:     entity.ProduceDate.Format("2006-01-02"),
			TotalTypesCount: count,
		})
	}
	resp.List = list
	return
}

func (l *ApiLogic) GetDetailApi(req *types.IdReq) (resp *types.ProductionDetailResp, err error) {
	resp = &types.ProductionDetailResp{}
	entities, err := service.ProductionPlanService.GetDetailListApi(l.ctx, req.Id)
	if err != nil {
		return nil, err
	}
	list := make([]*types.ProductionDetailList, 0)
	for _, entity := range entities {
		spu, err := service.SpuService.GetSpuDetailByIdApi(l.ctx, entity.SpuID)
		if err != nil {
			return resp, err
		}
		weight, err := service.ProductionSortingService.GetSortedWeight(l.ctx, entity.ID)
		if err != nil {
			return resp, err
		}
		list = append(list, &types.ProductionDetailList{
			CreatedAt:              utils.TimestampToString(entity.CreatedAt),
			ProductionPlanDetailID: entity.ID,
			ProductImageURL:        spu.ProductImageURL,
			SortedWeight:           weight.InexactFloat64(),
			SpuID:                  entity.SpuID,
			SpuName:                spu.Name,
			UnitName:               spu.UnitName,
			Weight:                 entity.Weight.InexactFloat64(),
		})
	}
	resp.List = list
	return
}

func (l *ApiLogic) SortingOneApi(req *types.ProductionStoreSortingOneReq) (resp *types.ProductionBatchNumberJson, err error) {
	resp = &types.ProductionBatchNumberJson{}
	accountInfo, err := auth.GetAccountInfo(l.svcCtx, l.Request)
	if err != nil {
		return nil, err
	}
	tx := dao.Use(l.svcCtx.MysqlDb).Begin()
	batchNumber, err := service.ProductionSortingService.CreateApi(l.ctx, tx, accountInfo.EnterpriseId, accountInfo.PersonId, accountInfo.PersonName, decimal.NewFromFloat(req.Weight), req.ProductionPlanDetailID, req.SpuID)
	if err != nil {
		err = tx.Rollback()
		if err != nil {
			return
		}
	}

	//增加成品库存
	warehouse, _ := service.WarehouseService.GetWarehouseByEnterpriseDefaultIdApi(l.ctx, accountInfo.EnterpriseId)
	err = service.SpuInventoryService.IncrInventoryApi(l.ctx, tx, accountInfo.EnterpriseId, warehouse.ID, req.SpuID, decimal.NewFromFloat(req.Weight))
	if err != nil {
		err = tx.Rollback()
		if err != nil {
			return
		}
	}
	if err = service.InventRecordService.CreateInventRecordApi(l.ctx, tx, &model.InventoryRecordEntity{
		EnterpriseID: accountInfo.EnterpriseId,         // 关联到enterprise表主键id
		SpuID:        req.SpuID,                        // 商品主键,关联到spu表主键id
		Types:        0,                                // 类型,0表示入库,1表示出库
		Source:       10,                               // 来源,0表示正常采购出入口,10表示生产发货出入口,20表示系统调拨
		WarehouseID:  warehouse.ID,                     // 仓库id,关联到warehouse表主键id
		ChangeCount:  decimal.NewFromFloat(req.Weight), // 变动数量
		ShelfID:      0,                                // 货位ID
		BatchNumber:  batchNumber,                      // 批次号
	}); err != nil {
		if err = tx.Rollback(); err != nil {
			return
		}
	}
	if err = tx.Commit(); err != nil {
		return
	}
	resp.ProductionBatchNumber = batchNumber
	return
}

func (l *ApiLogic) SortingFinishApi(req *types.ProductionStoreSortingFinishReq) (resp string, err error) {
	err = service.ProductionPlanService.ModifyStatusByIdsApi(l.ctx, []int64{req.ProductionPlanDetailID}, enum.ProductionStatusFinish)
	return
}

func (l *ApiLogic) GetSortingDetailApi(req *types.ProductionPlanDetailIDForm) (resp *types.ProductionPlanSortingDetailResp, err error) {
	resp = &types.ProductionPlanSortingDetailResp{}
	entities, err := service.ProductionSortingService.GetByPlanDetailID(l.ctx, req.ProductionPlanDetailID)
	if err != nil || len(entities) == 0 {
		return
	}
	spuId := entities[0].SpuID
	list := make([]*types.ProductionPlanSortingDetailList, 0)
	for _, entity := range entities {
		list = append(list, &types.ProductionPlanSortingDetailList{
			CreatedAt:             utils.TimestampToString(entity.CreatedAt),
			Operator:              entity.Operator,
			ProductionBatchNumber: entity.ProductionBatchNumber,
			Weight:                entity.Weight.InexactFloat64(),
		})
	}

	productionPlan, err := service.ProductionPlanService.GetProductionByDetailIDApi(l.ctx, req.ProductionPlanDetailID)
	sortedWeight, err := service.ProductionSortingService.GetSortedWeight(l.ctx, req.ProductionPlanDetailID)
	packageCount, err := service.ProductionSortingService.GetSortedPackage(l.ctx, req.ProductionPlanDetailID)
	spu, err := service.SpuService.GetSpuDetailByIdApi(l.ctx, spuId)
	if err != nil {
		return
	}
	resp.List = list
	resp.TotalWeight = sortedWeight.InexactFloat64()
	resp.PackageCount = packageCount
	resp.SpuName = spu.Name
	resp.ProductionImageURL = spu.ProductImageURL
	resp.ProductionPlanName = productionPlan.Name
	return
}

func (l *ApiLogic) LabelInfoApi(req *types.ProductionBatchNumberForm) (resp *types.ProductionPlanLabelResp, err error) {
	resp = &types.ProductionPlanLabelResp{}
	entity, err := service.ProductionSortingService.GetByBatchNumber(l.ctx, req.ProductionBatchNumber)
	if err != nil {
		return
	}
	spu, err := service.SpuService.GetSpuDetailByIdApi(l.ctx, entity.SpuID)
	if err != nil {
		return
	}
	resp = &types.ProductionPlanLabelResp{
		CategoryName:          spu.CategoryName,
		Deviation:             entity.Deviation.InexactFloat64(),
		ProduceDate:           entity.CreatedAt.Format("2006-01-02"),
		ProductionBatchNumber: entity.ProductionBatchNumber,
		SpuName:               spu.Name,
		UnitName:              spu.UnitName,
		Weight:                entity.Weight.InexactFloat64(),
	}
	return
}

func (l *ApiLogic) ResetSpuApi(req *types.ProductionPlanDetailIDJson) (resp string, err error) {
	tx := dao.Use(l.svcCtx.MysqlDb).Begin()
	if err = service.ProductionSortingService.ResetAll(l.ctx, tx, req.ProductionPlanDetailID); err != nil {
		if err = tx.Rollback(); err != nil {
			return
		}
	}
	if err = tx.Commit(); err != nil {
		return
	}
	return
}

func (l *ApiLogic) ResetOneApi(req *types.ProductionBatchNumberJson) (resp string, err error) {
	accountInfo, err := auth.GetAccountInfo(l.svcCtx, l.Request)
	if err != nil {
		return "", err
	}
	entity, err := service.ProductionSortingService.GetByBatchNumber(l.ctx, req.ProductionBatchNumber)
	if err != nil {
		return "", errors.New("生产批号有误")
	}

	tx := dao.Use(l.svcCtx.MysqlDb).Begin()
	if err = service.ProductionSortingService.ResetOne(l.ctx, tx, req.ProductionBatchNumber); err != nil {
		if err = tx.Rollback(); err != nil {
			return
		}
	}

	//减少成品库存
	warehouse, _ := service.WarehouseService.GetWarehouseByEnterpriseDefaultIdApi(l.ctx, accountInfo.EnterpriseId)
	err = service.SpuInventoryService.ReduceInventoryApi(l.ctx, tx, accountInfo.EnterpriseId, warehouse.ID, entity.SpuID, entity.Weight)
	if err != nil {
		if err = tx.Rollback(); err != nil {
			return
		}
	}

	if err = service.InventRecordService.CreateInventRecordApi(l.ctx, tx, &model.InventoryRecordEntity{
		EnterpriseID: accountInfo.EnterpriseId,  // 关联到enterprise表主键id
		SpuID:        entity.SpuID,              // 商品主键,关联到spu表主键id
		Types:        1,                         // 类型,0表示入库,1表示出库
		Source:       10,                        // 来源,0表示正常采购出入口,10表示生产分拣出入口,20表示发货出库出入口,30表示系统操作
		WarehouseID:  warehouse.ID,              // 仓库id,关联到warehouse表主键id
		ChangeCount:  entity.Weight,             // 变动数量
		ShelfID:      0,                         // 货位ID
		BatchNumber:  req.ProductionBatchNumber, // 批次号
	}); err != nil {
		if err = tx.Rollback(); err != nil {
			return
		}
	}

	if err = tx.Commit(); err != nil {
		return
	}
	return
}
